import java.util.HashMap;
import java.util.Map;
import java.util.Random;


public class Main2 {
	
	static final int STEP = 2;
	static final int WARM_UP_SIZE = 1000000;
	static final int STEP_COUNT = 15;
	static final int INIT_SIZE = 1000;
	static final int ATTEMPTS = 1000;
	static final double ATTEMPTS_PORTION = 0.05;
	static final int MIN_ATTEMPTS = 100;
	static Random rand = new Random();
	
	public static void main(String[] args) throws InterruptedException {
		
		warmUp();
		
		System.out.println("Performance");
		testPerformance();
		
		System.out.println("------------------------------");
		
		System.out.println("Memory");
		testMemory();
		
	}
	
	public static void warmUp() {
		Map<Integer, Integer> map = new HashMap<>(INIT_SIZE);
		for (int i = 0; i < WARM_UP_SIZE; i++) {
			map.put(rand.nextInt(Integer.MAX_VALUE), rand.nextInt(Integer.MAX_VALUE));
		}
		map = null;
		System.gc();
	}
	
	public static void testPerformance() {
		int size = INIT_SIZE;
		for (int iStep = 1; iStep < STEP_COUNT; iStep++) {
			Map<Integer, Integer> map = new HashMap<>(size * 2);
			fillMap(map, size);
			long timeBefore = System.nanoTime();
			int attemptCount = (int) Math.max(size * ATTEMPTS_PORTION, 100);
			for (int i = 0; i < attemptCount; i++) {
				map.put(rand.nextInt(Integer.MAX_VALUE), rand.nextInt(Integer.MAX_VALUE));
			}
			long timeAfter = System.nanoTime();
			
			System.out.println(size + "\t" + (timeAfter - timeBefore) / attemptCount);
			
			size *= STEP;
		}
	}
	
	public static void testMemory() throws InterruptedException {
		System.gc();
		Thread.sleep(10000); // Waiting for garbage collector
		int size = 1_000_000;
		long memoryBefore = Runtime.getRuntime().freeMemory();
		Map<Integer, Integer> map = new HashMap<>((int) (size * 1.2), 0.9F);
		for (int i = 0; i < size; i++) {
			map.put(rand.nextInt(Integer.MAX_VALUE), rand.nextInt(Integer.MAX_VALUE));
		}
		long memoryAfter = Runtime.getRuntime().freeMemory();
		System.out.println((memoryBefore - memoryAfter) / size);
	}
	
	private static void fillMap(Map<Integer, Integer> map, int size) {
		for (int i = 0; i < size; i++) {
			map.put(rand.nextInt(Integer.MAX_VALUE), rand.nextInt(Integer.MAX_VALUE));
		}
	}
	

}
